成品連結:Mouse Move Shadow、操作前程式碼、完成後程式碼
今天要做的是當滑鼠移動時,文字影子(text-shadow)跟著移動的效果,那就開始吧!
可以看到目前頁面上有一個 div.hero
,包著 h1
在裡面,而且 h1
當中的內容是可編輯的!這是因為 h1
中有 contenteditable="true"
的屬性使然。
首先先監聽要操作的元素,當滑鼠移動時執行 shadow
const hero = document.querySelector('.hero');
const text = hero.querySelector('h1');
hero.addEventListener('mousemove', shadow);
h1
區塊時座標會不正常?如果你試著在 shadow
中寫入 console.log(e.offsetX, e.offsetY)
,會發現當滑鼠移動到 h1
時座標會異常變化,仔細看會得知這時的 e.offsetX
& e.offsetY
的 e
變成了 h1
而不是 .hero
;因此當滑入 h1
左上角時e.offsetX
& e.offsetY
皆會變成 0。
解決辦法是判斷當進入 h1
時 e.offsetX
& e.offsetY
變成 h1.target.offsetLeft
以及 h1.target.offsetTop
但在這之前我們要將 e.offsetX
& e.offsetY
存入變數,以利在進入 h1
時可以作變動
function shadow(e) {
let {offsetX: x, offsetY: y} = e; // ES6 Destructuring
if (this !== e.target) { // this 指的是 .hero,這裡 if 的意思是當滑鼠進入 h1 時
x += e.target.offsetLeft; // 這裡的 e 是 h1 不是 .hero
y += e.target.offsetTop;
}
}
稍微說明一下,如果 e
是 .hero
,e.target.offsetLeft
& e.target.offsetTop
一直都會是 0,因為這兩個屬性是指相對於最接近的父層容器左邊及上方的距離。這樣講或許有些抽象,相關資訊可以參考下方連結的 HTMLElement.offsetLeft 以及 HTMLElement.offsetParent。
現在有了座標了,接著來做陰影吧!
目前畫面上預設有黑色的陰影,如果試著設定 text.style.textShadow = ${x}px ${y}px 10px rgba(0,0,0,1)
會發現陰影會移動,但並不如成品般圍繞著文字移動而已,而是有時候會超出頁面範圍。
因此我們要設定陰影所能移動的範圍
例如我們想要陰影最大移動的距離是 100px,也就是向上/下/左/右各 100px,因此我們先設定移動距離
const walk = 200; // 200px
接著就要計算如何讓陰影無論移動向哪個方向距離都是 100px,我們會需要用到 .hero
的常、寬,這裡已經先算好了
function shadow(e) {
// 省略上方 code
const {offsetWidth: width, offsetHeight: height} = hero;
const xWalk = Math.round((x / width * walk) - (walk / 2));
const yWalk = Math.round((y / height * walk) - (walk / 2));
}
假設左上角座標是(0,0)、右下角是(1000,800),寬剛分別為 1000、600,則算出來的 xWalk
與 yWalk
分別會是 -100、-100 以及 100, 100
接著再設定 CSS textShadow
屬性即可,如要設定多個陰影用逗號隔開即可
text.style.textShadow = `${xWalk}px ${yWalk}px 10px rgba(155,119,93,0.7), ${-xWalk}px ${-yWalk}px 10px rgba(240,226,205,0.7)`